#include "CUserStatus.h"
#include "CStatusCfg.h"
#include "commclass.h"
#include "../skill/CSkillAffect.h"
#include "../skill/CSkillEffect.h"
#include "../mainctrl.h"
#include "MsgGM.pb.h"
#include "MsgComm.pb.h"
#include "MsgMapInfo.pb.h"
#include "CTArray.h"
#include "CTSizeString.h"

/************************************************************************/
/*                    CStatusUnit                                       */
/************************************************************************/
int CStatusUnit::CalcStatusAddAttr(CPlayerAttr& stNewAttr,
        CPlayerAttr& stBaseAttr)
{
    int iIndex = 0;
    CStatusObj stStatusObj;
    stStatusObj._iResID = _iResID;
    stStatusObj._iAddNum = _chAddNum;
    
    iIndex = CMainCtrl::m_pstMain->m_stStatusMgr.FindSkillAffect(_iResID);
    if (iIndex < 0)
    {
        CT_TRACE(("status(%d) skill affect empty",_iResID));
        return 0;
    }

    CSkillAffect& stSkillAffect =
        CMainCtrl::m_pstMain->m_stStatusMgr.GetSkillAffect(iIndex);

    return CMainCtrl::m_pstMain->m_stStatusMgr.CalcStatusAddAttr(stSkillAffect,
            stNewAttr, stBaseAttr, stStatusObj);
}

/************************************************************************/
/*                    CUserStatus                                       */
/************************************************************************/
int CUserStatus::AddStatus(CStatusUnit& stStatusUnit)
{
    if (!stStatusUnit.IsValidID())
    {
        return ERROR_STATUS_OVER_RESID;
    }
    
    int iIndex = _stUserStatusHash.HashFind(stStatusUnit.GetResID());
    if (iIndex >= 0)
    {
        return ERROR_STATUS_REPEAT_RESID;
    }
    
    if (IsUserStatusFull())
    {
        return ERROR_STATUS_UNIT_FULL;
    }

    iIndex = _stUserStatusHash.HashAlloc(stStatusUnit.GetResID());
    if (iIndex < 0)
    {
        return RET_SYSTEM_FAIL;
    }

    _stUserStatusHash[iIndex] = stStatusUnit;

    return 0;
}

int CUserStatus::FindStatus(int iResID)
{
    //出错情况下只能返回负数 因为此接口正常情况下返回下标
    if (iResID <= 0)
    {
        CT_WARNING(("ResID(%d) invalid!", iResID));
        return -1;//因为返回下标 所以这里必须返回负数
    }

    int iIndex = _stUserStatusHash.HashFind(iResID);
    if (iIndex < 0)
    {
        return -1;//因为返回下标 所以这里必须返回负数
    }

    return iIndex;
}

int CUserStatus::FindStatus(int iResID, CStatusUnit& stStatusUnit)
{
    if (iResID <= 0)
    {
        return ERROR_STATUS_OVER_RESID;
    }

    int iIndex = _stUserStatusHash.HashFind(iResID);
    if (iIndex < 0)
    {
        return ERROR_STATUS_NOT_IN_ROLE;
    }

    stStatusUnit = _stUserStatusHash[iIndex];

    return 0;
}

int CUserStatus::DelStatus(int iResID)
{
    if (iResID <= 0)
    {
        return ERROR_STATUS_OVER_RESID;
    }

    int iIndex = _stUserStatusHash.HashFind(iResID);
    if (iIndex < 0)
    {
        return ERROR_STATUS_NOT_IN_ROLE;
    }

    return _stUserStatusHash.HashFreeByIndex(iIndex);
}

CStatusUnit& CUserStatus::GetStatus(int iIndex)
{
    return _stUserStatusHash[iIndex];
}

int CUserStatus::CalcStatusAddAttr(CPlayerAttr& stNewAttr)
{
    if (_stUserStatusHash.Size(T_USER_STATUS_HASH::USED_LIST) <= 0)
    {
        return 0;
    }

    int iRet = 0;
    CPlayerAttr stBaseAttr = stNewAttr;

    int iIndex = _stUserStatusHash.GetHeadIndex();

    while (iIndex >= 0)
    {
        iRet = _stUserStatusHash[iIndex].CalcStatusAddAttr(
            stNewAttr, stBaseAttr);
        CT_RETURN(iRet);

        iIndex = _stUserStatusHash.GetNextIndex(iIndex);
    }

    return 0;
}

int CUserStatus::GMStatusList(MsgAnsGMPlayer& stAns)
{
    int iIndex = 0;
    CTSizeString<MAX_BATTLE_NAME_BUFF> szNameStr;

    szNameStr.Cat("状态数量:%d\n",
        _stUserStatusHash.Size(T_USER_STATUS_HASH::USED_LIST));

    iIndex = _stUserStatusHash.GetHeadIndex();
    while (iIndex >= 0)
    {
        szNameStr.Cat("ID:%d ",_stUserStatusHash[iIndex].GetResID());
        szNameStr.Cat("叠加数:%d ",_stUserStatusHash[iIndex].GetAddNum());
        szNameStr.Cat("活动ID:%d ",_stUserStatusHash[iIndex].GetActID());
        szNameStr.Cat("到期时间:%d\n",_stUserStatusHash[iIndex].GetEndTime());

        iIndex = _stUserStatusHash.GetNextIndex(iIndex);
    }

    stAns.set_name(szNameStr.Get());
    return 0;
}

void CUserStatus::GetUserStatus(MsgAnsMapInfo& stMsgAnsMap)
{
    stMsgAnsMap.clear_status();

    if (_stUserStatusHash.Size(T_USER_STATUS_HASH::USED_LIST) <= 0)
    {
        return;
    }

    int iIndex = 0;
    int iAffectIndex = 0;
    unsigned int uiBufferID = 0;

    iIndex = _stUserStatusHash.GetHeadIndex();

    while (iIndex >= 0)
    {
        CStatusUnit& stStatusUnit = _stUserStatusHash[iIndex];
        uiBufferID = CMainCtrl::m_pstMain->m_stStatusMgr.GetBufferID(
            stStatusUnit.GetResID());

        if (uiBufferID > 0)//必须返回给前端的依据但是不能调用再次去FindHash的方法
        {
            MsgUserStatus* pstMsgStatusUnit = stMsgAnsMap.add_status();
            if (!pstMsgStatusUnit) {CT_WARNING(("pb pointer null!"));break;}

            pstMsgStatusUnit->set_status_id(uiBufferID);
            pstMsgStatusUnit->set_add_num(stStatusUnit.GetAddNum());
            pstMsgStatusUnit->set_expire_time(stStatusUnit.GetEndTime());

            iAffectIndex = CMainCtrl::m_pstMain->m_stStatusMgr.FindSkillAffect(
                stStatusUnit.GetResID());
            if (iAffectIndex >= 0)
            {
                CSkillAffect& stSkillAffect =
                    CMainCtrl::m_pstMain->m_stStatusMgr.GetSkillAffect(
                        iAffectIndex);
            
                for (int i = 0; i < stSkillAffect.GetSkillEffectSize(); ++i)
                {
                    CSkillEffect& stSkillEffect =
                        stSkillAffect.GetSkillEffect(i);
                
                    MsgKeyValueUnit* pstMsgKeyValueUnit =
                        pstMsgStatusUnit->add_key_value();
                    if (!pstMsgKeyValueUnit){CT_WARNING(("!!!"));continue;}
                    pstMsgKeyValueUnit->set_key(stSkillEffect.GetSubType());
                    pstMsgKeyValueUnit->set_value(
                        stSkillEffect.GetData() * stStatusUnit.GetAddNum());
                }
            }
        }

        iIndex = _stUserStatusHash.GetNextIndex(iIndex);
    }
}

int CUserStatus::GetStatusList(CStatusList& stStatusList, int iActType)
{
    if (_stUserStatusHash.Size(T_USER_STATUS_HASH::USED_LIST) <= 0)
    {
        return 0;
    }

    int iIndex = _stUserStatusHash.GetHeadIndex();

    while (iIndex >= 0)
    {
        CMainCtrl::m_pstMain->m_stStatusMgr.AddStatus(stStatusList,
            _stUserStatusHash[iIndex].GetResID(),
            _stUserStatusHash[iIndex].GetAddNum(),iActType);

        iIndex = _stUserStatusHash.GetNextIndex(iIndex);
    }

    return 0;
}

//判断时间到期或者活动结束的状态并直接删除
//变化的状态如果必须知会前端才返回真
void CUserStatus::UpdateUserStatus(bool& bHasChg)
{
    bHasChg = false;
    if (_stUserStatusHash.Size(T_USER_STATUS_HASH::USED_LIST) <= 0)
    {
        return;
    }

    if (CMainCtrl::m_pstMain->m_iNow <= GetLastUpdateTime())
    {
        return;
    }

    int iRet = 0;
    int iIndex = 0;
    short shActID = 0;
    CTLib::CTArray<int, MAX_STATUS_PLAYER_COUNT> aiStatusID;

    aiStatusID.Clear();

    iIndex = _stUserStatusHash.GetHeadIndex();

    while (iIndex >= 0)
    {
        CStatusUnit& stStatusUnit = _stUserStatusHash[iIndex];
        shActID = stStatusUnit.GetActID();
        if (stStatusUnit.GetEndTime() <= CMainCtrl::m_pstMain->m_iNow)
        {
            aiStatusID.AddOneItem(stStatusUnit.GetResID());
        }
        else if (shActID > 0 &&
            !CMainCtrl::m_pstMain->m_stActMgr.IsActOpen(shActID))
        {
            aiStatusID.AddOneItem(stStatusUnit.GetResID());
        }

        iIndex = _stUserStatusHash.GetNextIndex(iIndex);
    }

    for (int i = 0; i < aiStatusID.Size(); ++i)
    {
        iRet = DelStatus(aiStatusID[i]);
        if (iRet){CT_WARNING(("delete user status error(%d)!",iRet));}

        if (CMainCtrl::m_pstMain->m_stStatusMgr.IsNeedSendStatusList(
                aiStatusID[i]))
        {
            bHasChg = true;
        }
    }

    SetLastUpdateTime(CMainCtrl::m_pstMain->m_iNow);
}
